
#include <stdio.h>  /* gets */
#include <stdlib.h> /* atoi, malloc */
#include <string.h> /* strcpy */
#include "memory_allocation.h"
#include "set.h"


struct MemoryCache mem_cache_intset;

void intset_init_cache(void)
{
    mem_cache_init(&mem_cache_intset);
}

void *intset_malloc()
{
    void *ptr;
    ptr = mem_cache_get(&mem_cache_intset);
    if (ptr == NULL)
    {
        return (struct my_struct *)malloc(sizeof(struct my_struct));
    }
    else
    {
        return ptr;
    }
}

void *intset_itemfree(struct my_struct *ptr)
{
    int64_t status = mem_cache_add(&mem_cache_intset, (void *)ptr);
    if (status == 0)
    {
        free((void *)ptr);
    }
}

void intset_add(struct my_struct **map, int mykey)
{
    struct my_struct *s;
    HASH_FIND_INT(*map, &mykey, s); /* mykey already in the hash? */
    if (s == NULL)
    {
        s = intset_malloc();
        s->ikey = mykey;
        HASH_ADD_INT(*map, ikey, s); /* ikey: name of key field */
    }
}

void pm_intset_add(struct pm_int_set *int_set, int mykey)
{
    intset_add(&(int_set->data), mykey);
}

struct my_struct *find_user(struct my_struct **map, int mykey)
{
    struct my_struct *s;

    HASH_FIND_INT(*map, &mykey, s); /* s: output pointer */
    return s;
}

struct my_struct *intset_find(struct my_struct **map, int mykey)
{
    struct my_struct *s;

    HASH_FIND_INT(*map, &mykey, s); /* s: output pointer */
    return s;
}

int64_t pm_intset_has(struct pm_int_set *int_set, int mykey)
{
    struct my_struct *s;
    s = intset_find(&(int_set->data), mykey);
    if (s == NULL)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

void intset_remove(struct my_struct **map, int64_t user_id)
{
    struct my_struct *user = find_user(map, user_id);
    HASH_DEL(*map, user); /* user: pointer to deletee */
    free(user);
}

void pm_intset_remove(struct pm_int_set *int_set, int64_t user_id)
{
    intset_remove(&(int_set->data), user_id);
}

void intset_free(struct my_struct **map)
{
    struct my_struct *current_user, *tmp;

    HASH_ITER(hh, *map, current_user, tmp)
    {
        HASH_DEL(*map, current_user);  /* delete it (g_users advances to next) */
        intset_itemfree(current_user); /* free it */
    }
}

void pm_intset_free(struct pm_int_set *int_set)
{
    intset_free(&(int_set->data));
}

void intset_iterate(struct my_struct **map)
{
    struct my_struct *s;

    for (s = *map; s != NULL; s = (struct my_struct *)(s->hh.next))
    {
        printf("ikey %d\n", s->ikey);
    }
}

struct pm_int_set_iterator *start_iterate(struct my_struct **map)
{
    // struct my_struct *s;
    struct pm_int_set_iterator *iter;
    iter = (struct pm_int_set_iterator *)malloc(sizeof(struct pm_int_set_iterator));
    iter->current = *map;
    iter->ended = 0;
    iter->started = 0;
    return iter;
}

struct my_struct *next_item(struct my_struct **map_item)
{
    struct my_struct *next = (*map_item)->hh.next;
    return next;
}

struct pm_int_set_iterator *pm_intset_start_iterate(struct pm_int_set *int_set)
{
    return start_iterate(&(int_set->data));
}

int64_t pm_intset_next(struct pm_int_set_iterator *iter)
{
    if (iter->started == 1)
    {
        struct my_struct *s;
        return next_item(&(iter->current))->ikey;
    }
    else
    {
        iter->started = 1;
        return iter->current->ikey;
    }
}

int64_t pm_intset_ended(struct pm_int_set_iterator *iter)
{
    struct my_struct *s;
    return iter->ended;
}

void pm_intset_show(struct pm_int_set *int_set)
{
    intset_iterate(&(int_set->data));
}

int name_sort(struct my_struct *a, struct my_struct *b)
{
    return strcmp(a->value, b->value);
}

int id_sort(struct my_struct *a, struct my_struct *b)
{
    return (a->ikey - b->ikey);
}

struct pm_int_set *pm_intset_create()
{
    struct my_struct *g_users_1 = NULL;
    struct pm_int_set *int_set = NULL;
    int_set = (struct pm_int_set *)malloc(sizeof(int_set));
    int_set->data = NULL;
    return int_set;
}

int64_t count(struct my_struct **set)
{
    return HASH_COUNT(*set);
}

void write_values_into_buffer(struct my_struct **map, int64_t *buffer)
{
    struct my_struct *s;
    int64_t i = 0;
    for (s = *map; s != NULL; s = (struct my_struct *)(s->hh.next))
    {
        printf("wrote %d into buffer\n", s->ikey);
        buffer[i] = s->ikey;
        i += 1;
    }
}

int64_t *pm_intset_to_buffer(struct pm_int_set *int_set)
{
    int64_t num_users;
    int64_t length = count(&(int_set->data));
    int64_t *buffer = (int64_t *)malloc(sizeof(int64_t) * length);
    write_values_into_buffer(&(int_set->data), buffer);
    return buffer;
}
